﻿#include "plc_interface_base.h"


// 十六进制数组转十六进制字符串函数
// 1
void PLC_Interface_Base::HexByteArrayToHexString(const QByteArray &hexByteArr, int convertLen, QString &str)
{
    //获得目标数组大小
    int HexByteArrSize = hexByteArr.size();
    //判断长度是否合法，如果长度大于数组长度，则设为数组长度，小于0则设置为0
    if(convertLen > HexByteArrSize)
    {
        convertLen = HexByteArrSize;
    }
    else if(convertLen < 0)
    {
        convertLen = 0;
    }

    for(int i = 0; i < convertLen; i++)
    {
        str += QString("%1").arg((quint8)hexByteArr.at(i),2,16,QLatin1Char('0'));
    }
}
// 2
QString PLC_Interface_Base::HexByteArrayToHexString(const QByteArray &hexByteArr, int convertLen)
{
    QString str;
    HexByteArrayToHexString(hexByteArr, convertLen, str);

    return str;
}

// CRC校验码计算函数
// 1
void PLC_Interface_Base::CalculateCRC(const QString &checkStr, QString &checkStrCrc)
{
    quint8 buffer;  //定义中间变量
    quint16 wcrc16 = 0xFFFF; //预置CRC校验码，全为1
    QByteArray data  = QByteArray::fromHex(checkStr.toLocal8Bit());

    //循环计算每个数据
    for (int i = 0; i < data.size(); i++ )
    {
        buffer = data.at(i);
        wcrc16 = wcrc16 ^ buffer;
        for(int j = 0; j < 8; j++)
        {
            //判断右移出的是不是1，如果是1则与多项式进行异或
            if(wcrc16 & 0x0001)
            {
                //右移一位
                wcrc16 = wcrc16 >> 1;
                //异或
                wcrc16 = wcrc16 ^ 0xA001;
            }
            else
            {
                //如果不是1直接移出
                wcrc16 = wcrc16 >> 1;
            }
        }
    }

    //拼凑成4个16进制字符，空位补0
    checkStrCrc = QString("%1").arg(wcrc16, 4, 16, QLatin1Char('0'));

    //交换高低位
    QString leftBuffer = checkStrCrc.mid(0,2);
    QString rightBuffer = checkStrCrc.mid(2,2);
    //拼接
    checkStrCrc = rightBuffer + leftBuffer;
}
// 2
QString PLC_Interface_Base::CalculateCRC(const QString &checkStr)
{
    QString str;
    CalculateCRC(checkStr, str);

    return str;
}

// 判断报文CRC正确性函数
// 1
bool PLC_Interface_Base::JudgeCRC(const QByteArray &arr)
{
    QString checkStr, checkStrCrc, CRC;
    //取出crc校验码之前的数据，计算其crc校验码
    HexByteArrayToHexString(arr, arr.size() - 2, checkStr);
    CalculateCRC(checkStr, checkStrCrc);
    //取出报文中的CRC校验码，转换成CRC字符串
    QByteArray CRCArray = arr.right(2);
    HexByteArrayToHexString(CRCArray, 2, CRC);

    //比较两个CRC校验码是否相同
    if(checkStrCrc != CRC)
    {
        return false;
    }
    else
    {
        return true;
    }
}
// 2
bool PLC_Interface_Base::JudgeCRC(const QByteArray &arr, const QString &crc)
{
    QString checkStr, checkStrCrc;
    //取出crc校验码之前的数据，计算其crc校验码
    HexByteArrayToHexString(arr, arr.size() - 2, checkStr);
    CalculateCRC(checkStr, checkStrCrc);

    //比较两个CRC校验码是否相同
    if(checkStrCrc != crc)
    {
        return false;
    }
    else
    {
        return true;
    }
}

// 为报文数组末尾添加CRC检验码函数
void PLC_Interface_Base::AddCRCToByteArray(QByteArray &arr)
{
    //先将报文数组转为2位16进制字符串形式
    QString checkString = HexByteArrayToHexString(arr, (arr.size() - 2));

    //计算出响应报文的当前CRC校验码字符串
    QString CRCCheck = CalculateCRC(checkString);

    //添加CRC校验码到响应报文数组
    arr[arr.size() - 2] = CRCCheck.mid(0,2).toInt(NULL,16);
    arr[arr.size() - 1] = CRCCheck.mid(2,2).toInt(NULL,16);

}

// 连接两个quint8数据为一个quint16数据
// 1
quint16 PLC_Interface_Base::BondTwoUint8ToUint16(const quint8 &preNum, const quint8 &laterNum)
{
    quint16 bondNum;
    bondNum = (preNum << 8) | laterNum;
    return bondNum;
}
// 2
void PLC_Interface_Base::BondTwoUint8ToUint16(const quint8 &preNum, const quint8 &laterNum, quint16 &bondNum)
{
    bondNum = (preNum << 8) | laterNum;
}

// 字节反转函数
bool PLC_Interface_Base::ByteReverse(QString &str)
{
    //首先判断字符串长度是不是8位
    if(str.length() != 8)
    {
        return false;
    }

    // 定义临时字符变量
    QChar temp;

    for(int i=0; i < 4; i++)
    {
        temp = str[i];        // 将第i个元素存入临时字符变量
        str[i] = str[8-i-1];  // 将第i个字符元素和第n-i-1个元素对调
        str[8-i-1] = temp;    // 将临时字符变量的值赋给第n-i-1个元素
    }

    return true;
}

//返回串口类型函数
CommunicationType PLC_Interface_Base::GetCommunicationType()
{
    return commuType;
}

//返回通讯协议类型函数
CommunicationProtocol PLC_Interface_Base::GetCommunicationProtocol()
{
    return commuProtocal;
}

//获取当前请求报文数组
// 1
void PLC_Interface_Base::GetRequestMessage(QByteArray &requestMess)
{
    requestMess = RequestMessage;
}
// 2
QByteArray PLC_Interface_Base::GetRequestMessage()
{
    QByteArray requestMess;
    requestMess = RequestMessage;

    return requestMess;
}

//获取当前接收报文数组
// 1
void PLC_Interface_Base::GetReceiveMessage(QByteArray &receiveMess)
{
    receiveMess = ReceiveMessage;
}
// 2
QByteArray PLC_Interface_Base::GetReceiveMessage()
{
    QByteArray receiveMess;
    receiveMess = ReceiveMessage;

    return receiveMess;
}
